import urllib
import gviz_api

import statsdt
import statsdb
import statscons

from google.appengine.ext.webapp import template

class Formatter(object):
  def respond(self, reqHdlr, data):
    return
  
class JSONFormatter(Formatter):
  def respond(self, reqHdlr, data):
    reqHdlr.response.headers["Content-Type"] = "text/plain"      
    cols, rows, colOrder = self.fill(reqHdlr, data)
    
    if cols is None: return
      
    data_table = gviz_api.DataTable(cols)
    data_table.AppendData(rows)
    reqHdlr.response.out.write(data_table.ToJSonResponse(
          columns_order = colOrder,
          order_by = colOrder[0],
          req_id = self.getReqId(reqHdlr)))
  
  def getReqId(self, reqHdlr):
    #Get request tqx for response
    tqx = reqHdlr.request.get("tqx")
    reqId = 0
    if tqx:
      params = dict([p.split(":") for p in tqx.split(";")])
      reqId = params["reqId"]
  
  def fill(self, reqHdlr, data):
    return

class RecordJSONFormatter(JSONFormatter):
  def fill(self, reqHdlr, data):
    tags = reqHdlr.request.get("tags").split(" ")
    if 0 == len(data):
      reqHdlr.response.out.write("google.visualization.Query.setResponse(\
        {version:'0.5',reqId:'"+str(self.getReqId(reqHdlr))+"',status:'error',errors:\
        [{reason:'invalid_query',message:'Invalid query',\
        detailed_message:'No data found for "+" ".join(tags)+".'}]});")
      return None, None, None
                
    datefmt = str(reqHdlr.request.get("dfmt"))
    x = reqHdlr.request.get("x").split(" ")
    y = reqHdlr.request.get("y").split(" ")

    dtStats = self.getDTStats(data, x, y)
    return dtStats.fill(data, tags, datefmt, x, y)
  
  def getDTStats(self, results, x, y):
    if 0 == len("".join(x)) \
    and 0 == len("".join(y)):
      return statsdt.DTX()
    if "date" in x:
      return statsdt.DTX()
    if "date" in y:
      return statsdt.DTY()
    if not "date" in x \
    and not "date" in y:
      return statsdt.DTTags()
    # More conditions later    
    return statsdt.BaseStatsDT() #default
  
class NextTagJSONFormatter(JSONFormatter):
  def fill(self, reqHdlr, data):
    pagesize = 10
    if True == reqHdlr.request.get("pagesize").isdigit():
      pagesize = int(reqHdlr.request.get("pagesize"));

    cols = [("name", "string"),("refCount", "number"),("bookmark", "string")]
    rows = [[tag.name, len(tag.records), ""] for tag in data[0]]
    if len(rows)>0 \
    and len(rows) == pagesize:
        rows[-1][2] = "bookmark"
    colOrder = ["name", "refCount", "bookmark"]
    
    return cols, rows, colOrder

class RelatedTagJSONFormatter(JSONFormatter):
  def fill(self, reqHdlr, data):
    pagesize = 10
    if True == reqHdlr.request.get("pagesize").isdigit():
      pagesize = int(reqHdlr.request.get("pagesize"));

    cols = [("name", "string"),("refCount", "number"),("bookmark", "string")]
    rows = [[tag, 0, ""] for tag in data]
    colOrder = ["name", "refCount", "bookmark"]
    
    return cols, rows, colOrder

  
class HistoryJSONFormatter(JSONFormatter):
  def fill(self, reqHdlr, data):
    cols = [("tags", "string"),("qcount", "number")]
    rows = [["".join(history.tags), history.qcount] for history in data]
    colOrder = ["tags", "qcount"]
    
    return cols, rows, colOrder

class TagIndexJSONFormatter(JSONFormatter):
  def fill(self, reqHdlr, data):
    cols = [("tag", "string")]
    rows = [[t] for t in data]
    colOrder = ["tag"]
    
    return cols, rows, colOrder

class RecordHTMLFormatter(RecordJSONFormatter):
  def respond(self, reqHdlr, data):
    cols, rows, colOrder = self.fill(reqHdlr, data)
    chartType = "LineChart"
    
    if cols is None:
      jsonData = []
    else:
      data_table = gviz_api.DataTable(cols)
      data_table.AppendData(rows)
      jsonData = data_table.ToJSon(
                                   columns_order = colOrder,
                                   order_by = colOrder[0])
      if len(reqHdlr.request.get("charttype")) > 0:
        chartType = reqHdlr.request.get("charttype")
    values = {"pagehead": statscons.PageHead(reqHdlr.request.get("tags")),
              "query": reqHdlr.request.get("tags"),
              "charttype": chartType,
              "data": jsonData,
              "googleanalytics": statscons.GoogleAnalytics(),
              "appname": statscons.AppName(),
              }
    
    reqHdlr.response.out.write(template.render("./pages/charts.html", values))

class TagIndexHTMLFormatter(Formatter):
  def respond(self, reqHdlr, data):
    if 0 == len(reqHdlr.request.get("words")):
      reqHdlr.redirect("/querynexttag?output=html&pagesize=" + \
                       reqHdlr.request.get("pagesize"))
      return
    qc = len(data)
    data, navi = self.buildNavi(reqHdlr, reqHdlr.request.get("words"), data)
    tags = {}
    for tag in data:
      related, more = self.getRelated(tag)
      tags[tag] = (boldQuery(tag, reqHdlr.request.get("words")), related, more)
    
    values = {"pagehead": statscons.PageHead(reqHdlr.request.get("words")),
              "query": reqHdlr.request.get("words"),
              "resultsummary": statscons.ResultSummary(qc, reqHdlr.request.get("words")),
              "data": tags,
              "navi": navi,
              "googleanalytics": statscons.GoogleAnalytics(),
              "appname": statscons.AppName(),
              "searchform": statscons.SearchForm(reqHdlr.request.get("words")),
              }
    
    reqHdlr.response.out.write(template.render("./pages/results.html", values))
    
  def getRelated(self, tag):
    max = 5
    related = statsdb.GetRelatedTags(tag)[0][0:max]
    return related, max == len(related)
  
  def buildNavi(self, reqHdlr, query, data):
    pagesize = 10
    if True == reqHdlr.request.get("pagesize").isdigit():
      pagesize = int(reqHdlr.request.get("pagesize"));
    bookmark = 1
    if True == reqHdlr.request.get("bookmark").isdigit():
      bookmark = int(reqHdlr.request.get("bookmark"));
    maxbk = len(data)/pagesize
    if len(data) % pagesize:
      maxbk += 1
    start = (bookmark-1)*pagesize
    data = data[start:start+pagesize]

    i = 1
    maxPage = bookmark+9
    if maxPage > maxbk:
      maxPage = maxbk
    if bookmark > i:
      navi = self.buildNaviStr(query, pagesize, bookmark-1, statscons.PrevPage())
    else: navi = ""
    while i <= maxPage:
      navi += self.buildNaviStr(query, pagesize, i, str(i), i != bookmark)
      i += 1
    if bookmark < i-1:
      navi += self.buildNaviStr(query, pagesize, bookmark+1, statscons.NextPage())
    return data, navi
  
  def buildNaviStr(self, words,  pagesize, bookmark, display, href=True):
    if href:
      return """<span class="appTag"><a href="/querytagindex?words=""" + words + \
        "&pagesize=" + str(pagesize) + \
        "&bookmark=" + str(bookmark) + \
        """&output=html\">""" + display + "</a></span>"
    else:
      return """<span class="appTag"><span class="appQuery">""" + display + "</span></span>"

class NextTagHTMLFormatter(TagIndexHTMLFormatter):
  def respond(self, reqHdlr, data):
    data, navi = self.buildNavi(reqHdlr, "", data)
    tags = {}
    for tag in data:
      related, more = self.getRelated(tag.name)
      tags[tag.name] = (tag.name, related, more)
    values = {"pagehead": statscons.PageHead(),
              "query": "",
              "resultsummary": statscons.AllTags(),
              "data": tags,
              "navi": navi,
              "googleanalytics": statscons.GoogleAnalytics(),
              "appname": statscons.AppName(),
              "searchform": statscons.SearchForm(),
              }

    reqHdlr.response.out.write(template.render("./pages/results.html", values))   
  
  def buildNavi(self, reqHdlr, query, data):
    pagesize = 10
    if True == reqHdlr.request.get("pagesize").isdigit():
      pagesize = int(reqHdlr.request.get("pagesize"));
    pagenbr = 1
    if True == reqHdlr.request.get("pagenbr").isdigit():
      pagenbr = int(reqHdlr.request.get("pagenbr"));
    if 0 == len(reqHdlr.request.get("tag")):
      navi = ""
    else:
      # FIXME: if memcache is flushed, data[2](prev) is null, and client will jump to first page.
      navi = """<span class="appTag"><a href="/querynexttag?tag=""" + data[2] + \
          "&pagesize=" + str(pagesize) + \
          "&pagenbr=" + str(pagenbr-1) + \
          """&output=html">"""+statscons.PrevPage()+"</a></span>"

    navi += "<span class=\"appTag\">" + str((pagenbr-1)*pagesize+1) + "-" + str(pagenbr*pagesize) + "</span>"
    if data[1] is not None:
      navi += """<span class="appTag"><a href="/querynexttag?tag=""" + \
            data[1].name + \
            "&prevtag=" +  reqHdlr.request.get("tag") + \
            "&pagesize=" + str(pagesize) + \
            "&pagenbr=" + str(pagenbr+1) + \
            """&output=html">"""+statscons.NextPage()+"</a></span>"
    return data[0], navi

   
class RelatedTagHTMLFormatter(TagIndexHTMLFormatter):
  def respond(self, reqHdlr, data):
    qc = len(data)
    data, navi = self.buildNavi(reqHdlr, reqHdlr.request.get("tag"), data)
    tags = {}
    for tag in data:
      related, more = self.getRelated(reqHdlr.request.get("tag") + " " + tag)
      tags[reqHdlr.request.get("tag") + " " + tag] = \
        ("<span class=\"appQuery\">"+reqHdlr.request.get("tag")+"</span> "+tag, related, more)
    if 0 == len(tags):
#    or (1 == len(tags) \
#        and 0 == len(tags[reqHdlr.request.get("tag") + " " + tag][1])):
      url = "/queryrecord?tags="+ \
          urllib.quote(reqHdlr.request.get("tag").encode("utf-8"))+ \
          "&output=html"
      reqHdlr.redirect(url)
      return
    values = {"pagehead": statscons.PageHead(reqHdlr.request.get("tag")),
              "query": reqHdlr.request.get("tag"),
              "resultsummary": statscons.ResultSummary(qc, reqHdlr.request.get("tag")),
              "data": tags,
              "navi": navi,
              "googleanalytics": statscons.GoogleAnalytics(),
              "appname": statscons.AppName(),
              "searchform": statscons.SearchForm(reqHdlr.request.get("tag")),
              }

    reqHdlr.response.out.write(template.render("./pages/results.html", values))
    
  def buildNaviStr(self, words,  pagesize, bookmark, display, href=True):
    if href:
      return """<span class="appTag"><a href="/queryrelatedtag?tag=""" + words + \
        "&pagesize=" + str(pagesize) + \
        "&bookmark=" + str(bookmark) + \
        """&output=html\">""" + display + "</a></span>"
    else:
      return """<span class="appTag"><span class="appQuery">""" + display + "</span></span>"

class HistoryHTMLFormatter(Formatter):
  pass
    
def boldQuery(display, query):
  index = 0
  cursor = 0
  accum = ""
  while True:
    index = display.find(query, index)
    if -1 == index: break
    endIndex = index + len(query)
    part1 = display[cursor:index]
    part2 = display[index:endIndex]
    cursor = endIndex
    accum += part1+"<span class=\"appQuery\">"+part2+"</span>"

    index = endIndex

  accum += display[cursor:]
  return accum
